Two case studies one with a single image the other with multiple images and text
Import the libraries
import pandas as pd
import matplotlib.pyplot as plt
imagepath = "images/"
The data includes various climate indicators for a number of countries and regions (entities). We will be using the CO2 Concentrations data for the World as a whole
co2 is the dataframe that contains all of the data
co2world contains the data for the World entity
# Read the data
# original source: https://ourworldindata.org/co2-and-other-greenhouse-gas-emissions
co2 = pd.read_csv('data/climate-change.csv')
co2world = co2[co2['Entity']=='World']
co2world
| Entity | Year | CO2 concentrations | CH4 concentrations | N2O concentrations | February | September | Mass U.S. glaciers | CSIRO | IAP | MRIJMA | NOAA | Snow cover | Sea surface temp | Sea surface temp (lower-bound) | Sea surface temp (upper-bound) | IAP.1 | NOAA.1 | MRIJMA.1 | Arctic sea ice | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 847 | World | -803720 | 207.285440 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 848 | World | -803183 | 202.226839 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 849 | World | -802574 | 204.861938 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 850 | World | -802061 | 207.498645 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 851 | World | -801976 | 202.921723 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2774 | World | 2018 | 408.520833 | 1857.422500 | 330.914167 | NaN | NaN | NaN | NaN | 17.630567 | 16.642667 | 16.485767 | NaN | 0.61641 | 0.59350 | 0.63888 | 25.426967 | 22.427733 | 26.827333 | 4.79 |
| 2775 | World | 2019 | 411.419167 | 1866.669167 | 331.886667 | NaN | NaN | NaN | NaN | 18.933567 | 17.872667 | 17.489767 | NaN | 0.71702 | 0.69317 | 0.73946 | 27.445967 | NaN | 28.777333 | 4.36 |
| 2776 | World | 2020 | 413.943333 | 1879.103333 | 333.038333 | NaN | NaN | NaN | NaN | 20.007567 | 18.082667 | 17.287767 | NaN | 0.70991 | 0.68467 | 0.73446 | 29.420967 | NaN | 29.277333 | 4.00 |
| 2777 | World | 2021 | 416.106667 | 1895.455833 | 334.322500 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0.63219 | 0.60608 | 0.65442 | NaN | NaN | NaN | 4.92 |
| 2778 | World | 2022 | 417.652857 | 1908.336667 | 335.406667 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1932 rows × 20 columns
Set the ticks and labels so that it is more readable and define the x- and y-axis labels
Save the resulting figure as an image
co2world.plot(y="CO2 concentrations", x='Year', grid = True, figsize=(20,10))
plt.xticks([-800000, -600000, -400000, -200000, 0], ['800,000 BCE', '600,000 BCE', '400,000 BCE', '200,000 BCE','0'],
rotation=20)
plt.ylabel("carbon dioxode level (parts per million)")
plt.xlabel("years before today (0 = 1950)")
plt.savefig(f'{imagepath}co2world.png')
plt.legend("")
plt.title("CO2 Concentrations")
#co2world.tail(75)
Text(0.5, 1.0, 'CO2 Concentrations')
Code as before but now read in an image and display that with alpha setting 0.5 so it is in the bacjground
original image from NASA: https://www.nasa.gov/mission_pages/station/images/index.html

The result is a graph that contains the image - for an infographic we want the chart to be inside the boundaries of the image
So this is not the approach to take
ax = co2world.plot(y="CO2 concentrations", x='Year', grid = True, figsize=(20,10))
plt.xticks([-800000, -600000, -400000, -200000, 0], ['800,000 BCE', '600,000 BCE', '400,000 BCE', '200,000 BCE','0'],
rotation=20)
plt.ylabel("carbon dioxode level (parts per million)")
plt.xlabel("years before today (0 = 1950)")
plt.legend("")
plt.title("CO2 Concentrations")
bground=plt.imread(f'{imagepath}ISS_earth.en.jpg')
ax.imshow(bground, aspect='auto', alpha=0.5, extent=(-800000,20000,100,500))
plt.show()
We want the the infographic to look like this:

Original image: https://climate.nasa.gov/climate_resources/24/graphic-the-relentless-rise-of-carbon-dioxide/
So we change the original chart to add annotations
Save as image
color = 'darkblue'
fontsize = 24
ax = co2world.plot(y="CO2 concentrations", x='Year', linewidth= 2, color = 'darkred',grid = True, figsize=(20,10))
plt.xticks([-800000, -600000, -400000, -200000, 0],
['800,000 BCE', '600,000 BCE', '400,000 BCE', '200,000 BCE','0',], color = color, fontsize = fontsize)
plt.yticks(color = color,fontsize=fontsize)
plt.ylabel("carbon dioxode level (parts per million)",fontsize=fontsize, color =color)
plt.xlabel("years before today (0 = 1950)",fontsize=fontsize, color =color)
plt.savefig(f'{imagepath}co2world.png')
plt.legend("")
plt.title("CO2 Concentrations", weight='bold', fontsize=fontsize, color = color)
caption = "For millenia, atmospheric carbon has never been above this line "
plt.text(-790000,320, caption,
verticalalignment='top', horizontalalignment='left', fontsize=fontsize, color = color)
plt.plot([-800000,0],[305,305], linestyle = 'dashed', color='red', linewidth = 2)
plt.annotate("1950",xy = (0,312), xytext = (70000,306),
arrowprops=dict(facecolor= color, shrink=0.1), fontsize=fontsize, color = color)
plt.annotate("2022",xy = (0,417), xytext = (70000,411),
arrowprops=dict(facecolor= color, shrink=0.1), fontsize=fontsize, color = color)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
plt.savefig(f'{imagepath}co2.png', transparent = True)
plt.show()
The graph now looks like the one in the NASA image
Create a dummy chart 100x100, set alpha to 0 so it is invisible
imshow both images
fig, ax = plt.subplots(figsize=(20,10), layout = 'constrained')
ax.plot([0,100],[0,100], alpha = 0)
bground=plt.imread(f'{imagepath}ISS_earth.en.jpg')
img1 = plt.imread(f'{imagepath}co2.png')
ax.imshow(img1, aspect='auto', alpha=1, extent=(1,99,1,99))
ax.imshow(bground, aspect='auto', alpha=0.3, extent=(0,100,0,100))
plt.axis('off')
(0.0, 100.0, 0.0, 100.0)
# original source: https://github.com/owid/co2-data
co2 = pd.read_csv('data/owid-co2-data.csv')
co2
countries = co2.country.unique()
countries
continents = ['Europe','North America','South America','Asia','Oceania']
co2continents = co2[co2['country'].isin(continents)]
fig, ax = plt.subplots()
#ax = None
for c in continents:
ax = co2continents[co2continents['country']== c].plot(y='co2',x='year', label = c, linewidth = 2, ax = ax)
plt.savefig(f'{imagepath}co2Continents.png')
plt.show()
fig, ax = plt.subplots(figsize=(15,10), layout = 'constrained')
img1 = plt.imread(f'{imagepath}co2Continents.png')
img2 = plt.imread(f'{imagepath}co2.png')
bground = plt.imread(f'{imagepath}ISS_earth.en.jpg')
title = """
CO2 Emissions
"""
text1 = """
CO2 emissions have risen
significantly in all parts
of the World in modern times,
particulary in Asia.
"""
text2 = """
For hundreds of millenia,
CO2 levels never rose above
around 300ppm. In 1950 it
was just over 300 and now it
is over 400ppm
"""
# Create a figure that we can use as a canvas
ax.plot([0,100],[0,100], alpha = 0)
# Place the images on the canvas
ax.imshow(img1, aspect='auto', alpha=1, extent=(40,98,50,98))
ax.imshow(img2, aspect='auto', alpha=1, extent=(2,60,2,50))
ax.imshow(bground, aspect='auto', alpha=0.3, extent=(0,100,0,100))
# Add text to the canvas
ax.text(5,95, title,
verticalalignment='top', horizontalalignment='left',
color='red', fontsize=36, weight = 'bold')
ax.text(5,80, text1,
verticalalignment='top', horizontalalignment='left',
color='black', fontsize=18)
ax.text(65,40, text2,
verticalalignment='top', horizontalalignment='left',
color='black', fontsize=18)
# Switch off the ticks and bounding frame
plt.axis('off')
plt.savefig(f'{imagepath}CO2-info-graphic.png')